/*
 * @lc app=leetcode.cn id=591 lang=typescript
 *
 * [591] 标签验证器
 */

// @lc code=start
function isValid(code: string): boolean {
  const n = code.length;
  const stack = [];
  // 验证标签名是否合法
  const isValidateTagName = (tagname: string): boolean => {
    if (tagname.length < 1) return false;
    if (tagname.length > 9) return false;
    for (const c of tagname) {
      if (c < 'A' || c > 'Z') return false;
    }
    return true;
  };
  let i = 0;
  while (i < n) {
    if (code[i] === '<') {
      if (i === n - 1) return false;

      if (code[i + 1] === '/') {
        // 结束标签
        const j = code.indexOf('>', i);
        if (j < 0) return false;
        const tagName = code.slice(i + 2, j);
        // 栈为空，没有匹配的开始标签
        if (stack.length === 0) return false;
        // 开始标签和结束标签不匹配
        if (stack[stack.length - 1] !== tagName) return false;
        // 匹配成功，弹出栈顶元素
        stack.pop();
        i = j + 1;
        // 如果不是嵌套标签，也不是合法的标签
        if (stack.length === 0 && i !== n) return false;
      } else if (code[i + 1] === '!') {
        // CDATA
        if (stack.length === 0) return false;
        if (i + 9 > n) return false;
        const cdata = code.slice(i, i + 9);
        if (cdata !== '<![CDATA[') return false;
        const j = code.indexOf(']]>', i);
        if (j < 0) return false;
        i = j + 1;
      } else {
        // 开始标签
        const j = code.indexOf('>', i);
        if (j < 0) return false;
        const tagName = code.slice(i + 1, j);
        // 判断标签名是否合法
        if (!isValidateTagName(tagName)) return false;
        // 将合法开始标签压入栈中
        stack.push(tagName);
        i = j + 1;
      }
    } else {
      // 最少需要一个标签包裹
      if (stack.length === 0) return false;
      i++;
    }
  }
  return stack.length === 0;
}
// @lc code=end
